package com.idanchuang.component.config.apollo;

import com.idanchuang.component.config.apollo.support.RefreshFailedEvent;
import com.idanchuang.spi.config.IConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
import org.springframework.cloud.context.scope.refresh.RefreshScope;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

import java.util.List;

/**
 * @author yjy
 * @date 2020/1/6 17:04
 **/
@Order(Ordered.HIGHEST_PRECEDENCE)
public class BeforeRunner implements CommandLineRunner, ApplicationContextAware {

    private static final Logger log = LoggerFactory.getLogger(BeforeRunner.class);

    private IConfig iConfig;
    private RefreshScope refreshScope;
    private ApplicationContext applicationContext;
    @Autowired(required = false)
    private RefreshFailedEvent refreshFailedEvent;

    public BeforeRunner() {}

    public BeforeRunner(IConfig iConfig, RefreshScope refreshScope) {
        this.iConfig = iConfig;
        this.refreshScope = refreshScope;
    }

    @Override
    public void run(String... args) throws Exception {
        iConfig.addChangeListener((keys) -> {
            try {
                log.info("Found config changed, keys: {}", keys);
                // 更新相应的bean的属性值，主要是存在@ConfigurationProperties注解的bean
                this.applicationContext.publishEvent(new EnvironmentChangeEvent(keys));
                // 会导致数据库连接被关闭, 所以把它干掉, 经过测试, configBean 与 @Value 依然可以实现刷新
//                refreshScope.refreshAll();
            } catch (Exception e) {
                // 如果配置了刷新失败事件监听, 则触发事件
                if (refreshFailedEvent != null) {
                    try {
                        refreshFailedEvent.doEvent(keys, e);
                    } catch (Exception e1) {
                        log.error("invoke RefreshFailedEvent error", e1);
                    }
                }
            }
        });
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

}
